#include "rule.h"
#include "../global/global_declarations.h"
#include "stdlib.h"
#include "string.h"
#include "ctype.h"
#include "stdio.h"
#include "dictionary.h"
#include "../global/misc.h"
#include "../global/global_auth.h"
#include "../DEHT/deht.h"
#include <time.h>

/**
 * checks that the flag is either "all" or a number.
 */
bool check_flag(char* s) {
	if ((s != 0) && (strcmp(s, "all") == 0 || is_number(s)))
		return true;
	fprintf(stderr, "Error: flag must be either \"all\" or a number n.\n");
	return false;
}


/**
 * checks that all the arguments given in the command line are in the right platform.
 */
bool check_argv(char * argv[], int n) {
	if (n != 6) {
		fprintf(stderr, "Error: Usage exhaustive_table_generator <rule> <dictionary> <hash> <filenames prefix> <\"all\" or number of random password>\n");
		return false;
	}
	if (validate_rule(argv[1]) && check_Hash_name(argv[3]) && !check_deht_files_exists(argv[4]) && check_flag(argv[5]))
		return true;
	return false;
}


/**
 * inserts all the words in the rule to the DEHT.
 * @pre: d != NULL and initialized
 * @pre: func != NULL
 */
void scan_entire_rule(BasicHashFunctionPtr func, int output_length, DEHT* d) {
	int64 l, i;
	String* word;
	unsigned char hash_word[MAX_HASH_LENGTH] = {0};
	word = make_empty_string();
	l = count_words_in_whole_rule(the_rule, the_dictionary);
	calc_DEHT_last_block_per_bucket(d);
	for (i = 0; i < l; ++i) {
		word_k_for_rule(i, word);
		func((unsigned char*) word->data, word->size, hash_word);
		add_DEHT(d, hash_word, output_length, (unsigned char*) word->data,
				word->size);
		String_reset(word);
	}
	String_free(word);
}

/**
 * inserts n random words from the rule to the DEHT.
 * @pre: d != NULL and initialized
 * @pre: func != NULL
 */
void n_random_inserts(int n, DEHT* d, BasicHashFunctionPtr func,
		int output_length) {
	int random, i;
	int64 rule_size;
	String* word;
	unsigned char hash_word[MAX_HASH_LENGTH] = {0};
	word = make_empty_string();
	rule_size = count_words_in_whole_rule(the_rule, the_dictionary);
	for (i = 0; i < n; ++i) {
		random = rand();
		random = random % rule_size;
		word_k_for_rule(random, word);
		func((unsigned char*) word->data, word->size, hash_word);
		add_DEHT(d, hash_word, output_length, (unsigned char*) word->data,
				word->size);
		String_reset(word);
	}
	String_free(word);
}

/**
 *
 */
int main(int argc, char * argv[]) {

	char *prefix;
	String* rule, *flag;
	int64 num;
	int l;
	DEHT* d;
	BasicHashFunctionPtr func;
	if (check_argv(argv, argc) == false)
		return 1;

	srand(time(0));

	rule = make_string_from_char_arr(argv[1]);
	flag = make_string_from_char_arr(argv[5]);
	prefix = argv[4];
	func = which_hash(argv[3]);
	l = hash_Length(argv[3]);
	the_dictionary = create_dictionary_from_file(argv[2]);
	the_rule = make_rule_list_from_string(*rule);
	d = create_empty_DEHT(prefix, str_mod, keyTo64Bit, argv[3], 65536, 7, 8, 0);
	if (strcmp(flag->data, "all") == 0)
		scan_entire_rule(func, l, d);
	if (is_number(flag->data)) {
		num = String_to_int64(*flag);
		n_random_inserts(num, d, func, l);
	}

	lock_DEHT_files(d);
	String_free(rule);
	String_free(flag);
	free_rule(the_rule);
	free_dictionary(the_dictionary);
	free(d);

	return 0;
}
